package com.weds.frame.log.aop.log;

import cn.hutool.core.date.BetweenFormatter;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;

/**
 * Description:日志aop
 * Author: LiuWenQing
 * Datetime: 2023/3/20 10:57
 */
@Aspect
@ConditionalOnProperty(name = "log.active", matchIfMissing = false, havingValue = "true")
@Component
@Slf4j
public class LogAop {


    @Pointcut("(@annotation(org.springframework.web.bind.annotation.RequestMapping)) " +
            "|| (@annotation(org.springframework.web.bind.annotation.GetMapping)) " +
            "|| (@annotation(org.springframework.web.bind.annotation.PostMapping)) " +
            "|| (@annotation(org.springframework.web.bind.annotation.PutMapping)) " +
            "|| (@annotation(org.springframework.web.bind.annotation.PatchMapping)) " +
            "|| (@annotation(org.springframework.web.bind.annotation.DeleteMapping)) ")
    public void methodPointCut() {
    }

    @Around("methodPointCut()")
    public Object runTimeStatistics(ProceedingJoinPoint pjp) throws Throwable {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        Signature signature = pjp.getSignature();
        //被代理的类的类名
        String className = pjp.getTarget().getClass().getName();
        //方法名
        String methodName = signature.getName();
        if(methodName.equals("error")){
            return pjp.proceed();
        }
        //参数数组
        Object[] requestParams = pjp.getArgs();
        StringBuffer sb = new StringBuffer();
        for (Object requestParam : requestParams) {
            if(requestParam instanceof MultipartFile){
                // 文件参数
                sb.append("文件参数,");
            }else{
                if (requestParam !=null
                        && !StringUtils.isEmpty(requestParam.toString())) {
                    if(requestParam instanceof HttpServletRequest ||
                            requestParam instanceof HttpServletResponse){
                        continue;
                    }
                    sb.append(JSON.toJSONString(requestParam));
                    sb.append(",");
                }
            }
        }
        String requestParamsString = sb.toString();
        if (requestParamsString.length() > 0) {
            requestParamsString = requestParamsString.substring(0, requestParamsString.length() - 1);
        }
        //接口应答前打印日志
        log.info(String.format("【%s】类的【%s】方法，请求参数：%s", className, methodName, requestParamsString));
        //接口调用开始响应起始时间
        Date startDate = DateUtil.date();
        //正常执行方法，即让方法进行执行
        Object response = pjp.proceed();
        Date endDate = DateUtil.date();
        // 获取开始时间和结束时间的时间差
        long betweenDate = DateUtil.between(startDate, endDate, DateUnit.MS);
        // 格式化时间
        String formatBetween = DateUtil.formatBetween(betweenDate, BetweenFormatter.Level.MILLISECOND);
        String url = request.getRequestURI().substring(request.getContextPath().length());
        if (url.startsWith("/") && url.length() > 1) {
            url = url.substring(1);
        }
        //接口应答之后打印日志
//        log.info(String.format("【%s】类的【%s】方法，应答参数：%s", className, methodName, JSON.toJSONString(response)));
        //接口耗时
        log.info(String.format("请求接口【%s】总耗时：%s", url, formatBetween));

        return response;
    }
}
